//
//  MKUIFillingFlowLayoutConstraint.m
//  MKUI
//
//  Created by sushangjin on 2018/12/15.
//  Copyright © 2018 sushangjin. All rights reserved.
//

#import "MKUIFillingFlowLayoutConstraint.h"

@implementation MKUIFillingFlowLayoutConstraint

- (id)copyWithZone:(NSZone *)zone{
    MKUIFillingFlowLayoutConstraint *obj = [super copyWithZone:zone];
    obj.layoutDirection = self.layoutDirection;
    obj.layoutVerticalAlignment = self.layoutVerticalAlignment;
    obj.layoutHorizontalAlignment = self.layoutHorizontalAlignment;
    obj.contentInsets = self.contentInsets;
    return obj;
}
- (CGSize)sizeThatFits:(CGSize)size resizeItems:(BOOL)resizeItems{
	CGSize sizeFits = CGSizeZero;
	NSArray<id<MKUILayoutConstraintItemProtocol>> *items = self.layoutedItems;
	NSInteger count = items.count;
	if(count==0) return CGSizeZero;
	UIEdgeInsets contentInsets = self.contentInsets;
	CGSize limitSize = CGSizeMake(size.width-contentInsets.left-contentInsets.right, size.height-contentInsets.top-contentInsets.bottom);//限制在 size -contentInsets 矩形内
	CGFloat interitemSpacing = 0;
	
	MKCGAxis axis = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGAxisX:MKCGAxisY;
	MKCGAxis axisR = MKCGAxisReverse(axis);
	
	CGFloat maxLengthReverseAxis = 0;//元素的最大高度
	NSMutableArray<NSNumber *> *lengths = [[NSMutableArray alloc] initWithCapacity:items.count];
	for (id<MKUILayoutConstraintItemProtocol> item in items) {
		CGSize itemSize = CGSizeZero;
		if(resizeItems){
			if([item respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
				itemSize = [item sizeThatFits:limitSize resizeItems:resizeItems];
			}else if([item respondsToSelector:@selector(sizeThatFits:)]){
				itemSize = [item sizeThatFits:limitSize];
			}else{
				itemSize = [item sizeOfLayout];
			}
		}else{
			itemSize = [item sizeOfLayout];
		}
		CGFloat l = MKCGSizeGetLength(itemSize,axis);
		if(l>0){
			[lengths addObject:@(l)];
			maxLengthReverseAxis = MAX(maxLengthReverseAxis,MKCGSizeGetLength(itemSize,axisR));
			
			MKCGSizeSetLength(&itemSize, axis,MKCGSizeGetLength(limitSize, axis)+MKCGSizeGetLength(itemSize,axis)+interitemSpacing);
			MKCGSizeSetLength(&limitSize,axis ,MAX(MKCGSizeGetLength(limitSize, axis),0));
		}
	}
	MKCGSizeSetLength(&sizeFits, axis, MKCGSizeGetLength(size, axis));
	MKCGSizeSetLength(&sizeFits, axisR, maxLengthReverseAxis+MKUIEdgeInsetsGetEdge(contentInsets,axisR,MKUIEdgeInsetsMin)+MKUIEdgeInsetsGetEdge(contentInsets,axisR,MKUIEdgeInsetsMax));
	
	return sizeFits;
}
- (CGSize)sizeThatFits:(CGSize)size{
	return [self sizeThatFits:size resizeItems:NO];
}
- (void)layoutItemsWithResizeItems:(BOOL)resizeItems{
	NSArray<id<MKUILayoutConstraintItemProtocol>> *items = self.layoutedItems;
	NSInteger count = items.count;
	if(count==0)return;
	UIEdgeInsets contentInsets = self.contentInsets;
	CGRect bounds = UIEdgeInsetsInsetRect(self.bounds, contentInsets);
	CGSize limitSize = bounds.size;

	MKCGAxis axis = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGAxisX:MKCGAxisY;
//	MKCGAxis axisR = MKCGAxisReverse(axis);
	MKCGRectAlignment align = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGRectAlignmentFromMKUILayoutConstraintVerticalAlignment(self.layoutVerticalAlignment):MKCGRectAlignmentFromMKUILayoutConstraintHorizontalAlignment(self.layoutHorizontalAlignment);
	//分布局头尾元素
	id<MKUILayoutConstraintItemProtocol> firstItem = items.firstObject;
	id<MKUILayoutConstraintItemProtocol> lastItem = items.count>1?items.lastObject:nil;
	NSArray<id<MKUILayoutConstraintItemProtocol>> *middleItems = items.count>2?[items subarrayWithRange:NSMakeRange(1, items.count-2)]:@[];
	CGRect middleItemsBounds = bounds;
	//布局头元素
	if(firstItem){
		id<MKUILayoutConstraintItemProtocol> item = firstItem;
		CGRect itemFrame = bounds;
		CGSize itemSize = CGSizeZero;
		if(resizeItems){
			if([item respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
				itemSize = [item sizeThatFits:limitSize resizeItems:resizeItems];
			}else if([firstItem respondsToSelector:@selector(sizeThatFits:)]){
				itemSize = [item sizeThatFits:limitSize];
			}else{
				itemSize = [item sizeOfLayout];
			}
		}else{
			itemSize = [item sizeOfLayout];
		}
		itemFrame.size = itemSize;
		MKCGRectSetMin(&itemFrame,axis,MKCGRectGetMin(bounds,axis));
		MKCGRectSetMin(&middleItemsBounds,axis,MKCGRectGetMax(itemFrame,axis));
		MKCGRectSetLength(&middleItemsBounds,axis,MKCGRectGetMax(bounds,axis)-MKCGRectGetMin(middleItemsBounds, axis));
		MKCGSizeSetLength(&limitSize, axis, MKCGSizeGetLength(limitSize, axis)-MKCGRectGetLength(itemFrame,axis));
		MKCGRectAlignToRect(&itemFrame,MKCGAxisReverse(axis),align,bounds);
		firstItem.layoutFrame = itemFrame;
	}
	//布局尾元素
	if(lastItem){
		id<MKUILayoutConstraintItemProtocol> item = lastItem;
		CGRect itemFrame = bounds;
		CGSize itemSize = CGSizeZero;
		if(resizeItems){
			if([item respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
				itemSize = [item sizeThatFits:limitSize resizeItems:resizeItems];
			}else if([firstItem respondsToSelector:@selector(sizeThatFits:)]){
				itemSize = [item sizeThatFits:limitSize];
			}else{
				itemSize = [item sizeOfLayout];
			}
		}else{
			itemSize = [item sizeOfLayout];
		}
		itemFrame.size = itemSize;
		MKCGRectSetMin(&itemFrame, axis, MKCGRectGetMax(bounds, axis)-MKCGRectGetLength(itemFrame,axis));
		MKCGRectSetLength(&middleItemsBounds, axis, MKCGRectGetMin(itemFrame, axis)-MKCGRectGetMin(middleItemsBounds,axis));
		MKCGSizeSetLength(&limitSize, axis, MKCGSizeGetLength(limitSize, axis)-MKCGRectGetLength(itemFrame, axis));
		MKCGRectAlignToRect(&itemFrame, MKCGAxisReverse(axis), align, bounds);
		lastItem.layoutFrame = itemFrame;
	}
	//布局中间元素
	if(middleItems.count){
		NSMutableArray<NSValue *> *itemSizes = [[NSMutableArray alloc] initWithCapacity:middleItems.count];//每个元素的尺寸
		for (id<MKUILayoutConstraintItemProtocol> item in middleItems) {
			CGSize itemSize = CGSizeZero;
			if(resizeItems){
				if([item respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
					itemSize = [item sizeThatFits:limitSize resizeItems:resizeItems];
				}else if([firstItem respondsToSelector:@selector(sizeThatFits:)]){
					itemSize = [item sizeThatFits:limitSize];
				}else{
					itemSize = [item sizeOfLayout];
				}
			}else{
				itemSize = [item sizeOfLayout];
			}
			MKCGSizeSetLength(&limitSize, axis, MKCGSizeGetLength(limitSize, axis)-MKCGSizeGetLength(itemSize, axis));
			[itemSizes addObject:[NSValue valueWithCGSize:itemSize]];
		}
		CGFloat space = 0;//每个元素之间的间隔
		CGFloat sum = 0;
		for (NSValue *v in itemSizes) {
			CGSize itemSize = [v CGSizeValue];
			sum += MKCGSizeGetLength(itemSize, axis);
		}
		space = (MKCGRectGetLength(middleItemsBounds, axis)-sum)/(middleItems.count+1);
		CGRect itemFrame = middleItemsBounds;
		for (int i=0; i<middleItems.count; i++) {
			id<MKUILayoutConstraintItemProtocol> item = middleItems[i];
			CGSize itemSize = [itemSizes[i] CGSizeValue];
			itemFrame.size = itemSize;
			MKCGRectSetMin(&itemFrame, axis, MKCGRectGetMin(itemFrame, axis)+space);
			MKCGRectAlignToRect(&itemFrame, MKCGAxisReverse(axis), align , bounds);
			item.layoutFrame = itemFrame;
			MKCGRectSetMin(&itemFrame, axis, MKCGRectGetMin(itemFrame, axis)+MKCGRectGetLength(itemFrame, axis));
		}
	}
}
- (void)layoutItems{
	[self layoutItemsWithResizeItems:NO];
}
@end

MKDEF_EnumTypeCategories(MKUIFillingFlowLayoutConstraintParam,
(@{
   @(MKUIFillingFlowLayoutConstraint_H_C):@"H_C",
   @(MKUIFillingFlowLayoutConstraint_H_T):@"H_T",
   @(MKUIFillingFlowLayoutConstraint_H_B):@"H_B",
   @(MKUIFillingFlowLayoutConstraint_V_C):@"V_C",
   @(MKUIFillingFlowLayoutConstraint_V_L):@"V_L",
   @(MKUIFillingFlowLayoutConstraint_V_R):@"V_R",
   }))
@implementation MKUIFillingFlowLayoutConstraint (InitMethod)
//////////////////////////////////////////////////////////////////////////////
+ (NSDictionary<NSNumber *,NSArray<NSNumber *> *> *)ConstraintParamMapOfHorizontal{
	static NSDictionary<NSNumber *,NSArray<NSNumber *> *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSMutableDictionary<NSNumber *,NSArray<NSNumber *> *> *map = [[NSMutableDictionary alloc] init];
		map[@(MKUIFillingFlowLayoutConstraint_H_C)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentCenter),
		  ];
		map[@(MKUIFillingFlowLayoutConstraint_H_T)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentTop),
		  ];
		map[@(MKUIFillingFlowLayoutConstraint_H_B)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentBottom),
		  ];
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSNumber *,NSArray<NSNumber *> *> *)ConstraintParamMapOfVertical{
	static NSDictionary<NSNumber *,NSArray<NSNumber *> *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSMutableDictionary<NSNumber *,NSArray<NSNumber *> *> *map = [[NSMutableDictionary alloc] init];
		map[@(MKUIFillingFlowLayoutConstraint_V_C)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentCenter),
		  ];
		map[@(MKUIFillingFlowLayoutConstraint_V_L)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentLeft),
		  ];
		map[@(MKUIFillingFlowLayoutConstraint_V_R)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentRight),
		  ];
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSArray<NSNumber *> *,NSNumber *> *)ConstraintParamRevertMapOfHorizontal{
	static NSDictionary<NSArray<NSNumber *> *,NSNumber *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self ConstraintParamMapOfHorizontal];
		NSMutableDictionary<NSArray<NSNumber *> *,NSNumber *> *map = [[NSMutableDictionary alloc] initWithCapacity:ConstraintParamMap.count];
		for (NSNumber *key in ConstraintParamMap) {
			map[ConstraintParamMap[key]] = key;
		}
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSArray<NSNumber *> *,NSNumber *> *)ConstraintParamRevertMapOfVertical{
	static NSDictionary<NSArray<NSNumber *> *,NSNumber *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self ConstraintParamMapOfVertical];
		NSMutableDictionary<NSArray<NSNumber *> *,NSNumber *> *map = [[NSMutableDictionary alloc] initWithCapacity:ConstraintParamMap.count];
		for (NSNumber *key in ConstraintParamMap) {
			map[ConstraintParamMap[key]] = key;
		}
		__share__ = map;
	});
	return __share__;
}
+ (void)parseConstraintParam:(MKUIFillingFlowLayoutConstraintParam)param layoutDirection:(MKUILayoutConstraintDirection *)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment *)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment *)layoutHorizontalAlignment{
	NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMapOfHorizontal = [self.class ConstraintParamMapOfHorizontal];
	NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMapOfVertical = [self.class ConstraintParamMapOfVertical];
	NSArray<NSNumber *> *enums = ConstraintParamMapOfHorizontal[@(param)];
	if(enums){
		*layoutDirection = [enums[0] integerValue];
		*layoutVerticalAlignment = [enums[1] integerValue];
	}else{
		enums = ConstraintParamMapOfVertical[@(param)];
		*layoutDirection = [enums[0] integerValue];
		*layoutHorizontalAlignment = [enums[1] integerValue];
	}
}
+ (MKUIFillingFlowLayoutConstraintParam)constraintParamWithLayoutDirection:(MKUILayoutConstraintDirection)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment)layoutHorizontalAlignment{
	MKUIFillingFlowLayoutConstraintParam param;
	if(layoutDirection==MKUILayoutConstraintDirectionHorizontal){
		NSDictionary<NSArray<NSNumber *> *,NSNumber *> *ConstraintParamRevertMapOfHorizontal = [self.class ConstraintParamRevertMapOfHorizontal];
		param = (MKUIFillingFlowLayoutConstraintParam)[ConstraintParamRevertMapOfHorizontal[@[@(layoutDirection),@(layoutVerticalAlignment)]] integerValue];
	}else{
		NSDictionary<NSArray<NSNumber *> *,NSNumber *> *ConstraintParamRevertMapOfVertical = [self.class ConstraintParamRevertMapOfVertical];
		param = (MKUIFillingFlowLayoutConstraintParam)[ConstraintParamRevertMapOfVertical[@[@(layoutDirection),@(layoutHorizontalAlignment)]] integerValue];
	}
	return param;
}
//////////////////////////////////////////////////////////////////////////////
- (id)initWithItems:(NSArray<id<MKUILayoutConstraintItemProtocol>> *)items constraintParam:(MKUIFillingFlowLayoutConstraintParam)param contentInsets:(UIEdgeInsets)contentInsets{
	if(self=[self init]){
		self.items = items;
		[self configWithConstraintParam:param];
		self.contentInsets = contentInsets;
	}
	return self;
}
- (MKUIFillingFlowLayoutConstraintParam)constraintParam{
	MKUIFillingFlowLayoutConstraintParam param = [self.class constraintParamWithLayoutDirection:self.layoutDirection layoutVerticalAlignment:self.layoutVerticalAlignment layoutHorizontalAlignment:self.layoutHorizontalAlignment];
	return param;
}
- (void)setConstraintParam:(MKUIFillingFlowLayoutConstraintParam)constraintParam{
	[self configWithConstraintParam:constraintParam];
}
- (void)configWithConstraintParam:(MKUIFillingFlowLayoutConstraintParam)param{
	MKUILayoutConstraintDirection layoutDirection;
	MKUILayoutConstraintVerticalAlignment layoutVerticalAlignment;
	MKUILayoutConstraintHorizontalAlignment layoutHorizontalAlignment;
	[self.class parseConstraintParam:param layoutDirection:&layoutDirection layoutVerticalAlignment:&layoutVerticalAlignment layoutHorizontalAlignment:&layoutHorizontalAlignment];
	self.layoutDirection = layoutDirection;
	self.layoutVerticalAlignment = layoutVerticalAlignment;
	self.layoutHorizontalAlignment = layoutHorizontalAlignment;
}
@end
